require 'digest/sha1'

class User < ActiveRecord::Base
  include Authentication
  include Authentication::ByPassword
  include Authentication::ByCookieToken

  belongs_to :city

  has_many :measures #, :dependent => :destroy :through => :tracks,
      has_many :tracks #, :dependent => :destroy
  has_many :measurements_tags
  belongs_to :city

  self.table_name = 'users'

  #images
  mount_uploader :image_url, ImageUploader

  validates :login, :presence   => true,
                    :uniqueness => true,
                    :length     => { :within => 3..40 },
                    :format     => { :with => Authentication.login_regex, :message => Authentication.bad_login_message }

  validates :email, :presence   => true,
                    :uniqueness => true,
                    :format     => { :with => Authentication.email_regex, :message => Authentication.bad_email_message },
                    :length     => { :within => 6..100 }


  validates_presence_of :phonemodel
  #gem validates password

  #validates city
  validates :city, :presence => true

  #wont do activation as of now
  #before_create :make_activation_code

  # HACK HACK HACK -- how to do attr_accessible from here?
  # prevents a user from submitting a crafted form that bypasses activation
  # anything else you want your user to change should be added here.
  attr_accessible :login, :email, :name, :password, :password_confirmation, :password_reset_code,
                  :public, :phonemodel, :image_url, :role
  attr_accessor :location

  # Activates the user in the database.
=begin
  def activate!
    @activated = true
    self.activated_at = Time.now.utc
    self.activation_code = nil
    save(:validate => false)
  end


  # Returns true if the user has just been activated.
  def recently_activated?
    @activated
  end

  def active?
    # the existence of an activation code means they have not activated yet
    activation_code.nil?
  end
=end

  # Authenticates a user by their login name and unencrypted password.  Returns the user or nil.
  #
  # uff.  this is really an authorization, not authentication routine.
  # We really need a Dispatch Chain here or something.
  # This will also let us return a human error message.
  #
  def self.authenticate(login, password)
    return nil if login.blank? || password.blank?
    u = where(['login = ?', login]).first # need to get the salt
    u && u.authenticated?(password) ? u : nil
  end

  def login=(value)
    write_attribute :login, (value ? value.downcase : nil)
  end

  def email=(value)
    write_attribute :email, (value ? value.downcase : nil)
  end

  #def make_activation_code
  #    self.activation_code = self.class.make_token
  #end

  def recent_taggings(lim = 10)
    MeasurementsTag.select("tag_name").where("user_id = #{self.id}").group("tag_name").limit(lim).all
  end

  def prominent_tags
    MeasurementsTag.select("tag_name, count(tag_name) as count")
      .where("user_id = #{self.id}").group("tag_name")
      .order("count(tag_name) desc").limit(10)
        #select tag_name, count(tag_name) from measurements_tags
        #where user_id =  52 group by tag_name
        #order by count(tag_name) desc
  end

  # ------- forgot password -----------

  def forgot_password
    @forgotten_password = true
    self.make_password_reset_code
  end

  def make_password_reset_code
    self.password_reset_code = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )
  end

  def reset_password
    # First update the password_reset_code before setting the reset_password
    # flag to avoid duplicate email notifications.
    update_attributes(:password_reset_code => nil)
    @reset_password = true
  end

  # #used in user_observer
  def recently_forgot_password?
    @forgotten_password
  end

  def recently_reset_password?
    @reset_password
  end

  def emailer_callback
    UserMailer.delay.forgot_password(self) if self.recently_forgot_password?     #queue up as a DJ job
    #UserMailer.reset_password(self).deliver if self.recently_reset_password?
  end

  # ---------- json serialization ------------
  def as_json(options = { })
    u = super(options.reverse_merge(:only => [:id, :city_id, :login, :created_at, :device]))
    u
  end
end